package javax.microedition.media;
        
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Vector;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Transmitter;

class MidiAudioPlayer implements Player,MetaEventListener {
    private Sequence sequence=null;
    private Sequencer sequencer=null;
    private Vector vListeners=null;
    private int iLoopCount=1;
    
    public boolean open(InputStream stream,String type) {
        try {
            sequencer=MidiSystem.getSequencer();
            sequencer.open();
            Synthesizer synth=MidiSystem.getSynthesizer();
            synth.open();
            Transmitter transmitter=sequencer.getTransmitter();
            Receiver receiver=synth.getReceiver();
            transmitter.setReceiver(receiver);
            sequence=MidiSystem.getSequence(stream);
            sequencer.setSequence(sequence);
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(MidiUnavailableException e) {
            e.printStackTrace();
        }
        catch(InvalidMidiDataException e) {
            e.printStackTrace();
        }
        return false;
    }
    
    protected void dispose() {
        close();
    }
    
    public void addPlayerListener(PlayerListener playerListener) {
        if(vListeners==null)
            vListeners=new Vector();
        vListeners.add(playerListener);
    }
    
    public void deallocate() {
        
    }
    
    public String getContentType() {
        return "audio/midi";
    }
    
    public long getDuration() {
        return 0;
    }
    
    public long getMediaTime() {
        if(sequencer!=null) {
            return sequencer.getMicrosecondPosition();
        }
        return 0;
    }
    
    public int getState() {
        return 0;
    }
    
    public void prefetch() throws MediaException {
        
    }
    
    public void realize() throws MediaException {
        
    }
    
    public void removePlayerListener(PlayerListener playerListener) {
        if(vListeners==null)
            return;
        for(Iterator it=vListeners.iterator();it.hasNext();) {
            PlayerListener listener=(PlayerListener)it.next();
            if(listener==playerListener) {
                vListeners.remove(playerListener);
                break;
            }
        }
    }
    
    public void setLoopCount(int count) {
        iLoopCount=count;
    }
    
    public long setMediaTime(long now) throws MediaException {
        if(sequencer!=null)
            sequencer.setMicrosecondPosition(now);
        return now;
    }
    
    public void start() throws MediaException {
        if(sequencer!=null) {
            sequencer.addMetaEventListener(this);
            sequencer.start();
        }
    }
    
    public void stop() throws MediaException {
        if(sequencer!=null) {
            sequencer.stop();
        }
    }
    
    public Control getControl(String controlType) {
        return null;
    }
    
    public Control[] getControls() {
        return null;
    }
    
    public void meta(MetaMessage event) {
        if(event.getType()==47) {
            iLoopCount--;
            if(iLoopCount>0) {
                sequencer.setMicrosecondPosition(0);
                try {
                    start();
                } catch(MediaException e) {
                    e.printStackTrace();
                }
            }
            else {
                close();
                if(vListeners!=null) {
                    for(Iterator it=vListeners.iterator();it.hasNext();) {
                        PlayerListener listener=(PlayerListener)it.next();
                        listener.playerUpdate(this,PlayerListener.END_OF_MEDIA,null);
                    }
                }
            }
        }
    }
    
    public void close() {
        Manager.mediaDone(this);
        if(sequencer!=null)
            sequencer.close();
    }
}